package com.desire.test;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/**
 * @author desire
 */
public class _35_流的中间_终止操作 {

    public static void main(String[] args) {
     /*
     匹配、聚合操作
        allMatch:接收一个Predicate 函数，当流中每个元素都符合该断言时才返回true，否则返回false
        noneMatch:接收一个Predicate 函数，当流中每个元素都不符合该断言时才返回true，否则返回false
        anyMatch:接收一个 Predicate 函数，只要流中有一个元素满足该断言则返回true，否则返回false
        findFirst:返回流中第一个元素
        findAny:返回流中的任意元素
        count:返回流中元素的总个数
        max:返回流中元素最大值
        min:返回流中元素最小值

      */
        /*
          归约reduce
            现在我的目标不是返回一个新的集合，而是希望对经过参数化操作后的集合进行进一步的运算，
            那么我们可用对集合实施归约操作。java8的流式处理提供了reduce方法来达到这一目的。
         */

        var ss = Stream.of(1, 2, 3, 4, 5);
        //var sum = ss.reduce(Integer::sum).get();
        // System.out.println(sum);

//        var j = ss.reduce((a, b) -> a * b).get();
//        System.out.println(j);

        // 求和   不用for循环求1-100 的和  考验对java8的Stream流的技术掌握
        var ii = IntStream.rangeClosed(1, 100);
        System.out.println(ii.sum());
    }

    public static void main5(String[] args) {
        /*


        collect收集
            利用collect(Collectors.toList())是一个简单的收集操作，是对处理结果的封装，对应的还有toSet、toMap，
            以满足我们对于结果组织的需求。这些方法均来自于java.util.stream.Collectors，我们可以称之为收集器。
            收集器也提供了相应的归约操作，但是与reduce在内部实现上是有区别的，收集器更加适用于可变容器上的归约操作，
            这些收集器广义上均基于Collectors.reducing()实现。
         */
        /*Integer ages = list.stream().filter(student -> "清华大学".equals(student.school)).mapToInt(User::getAge).sum();
        System.out.println(ages);
        System.out.println("归约 - - 》 start ");
        Integer ages2 = list.stream().filter(student -> "清华大学".equals(student.school)).map(User::getAge).reduce(0, (a, c) -> a + c);
        Integer ages3 = list.stream().filter(student -> "清华大学".equals(student.school)).map(User::getAge).reduce(0, Integer::sum);
        Integer ages4 = list.stream().filter(student -> "清华大学".equals(student.school)).map(User::getAge).reduce(Integer::sum).get();
        System.out.println(ages2);
        System.out.println(ages3);
        System.out.println(ages4);*/


        var is = Stream.of(
                new Students(1, "李四", "男", 18),
                new Students(22, "James Gosling", "男", 68),
                new Students(2, "张三", "男", 28),
                new Students(3, "王五", "男", 38),
                new Students(1, "李四", "男", 18),
                new Students(4, "李丽", "女", 25)
        );

        //IntStream iii = is.mapToInt(Students::getAge);
        //System.out.println(iii.count());  // 6

        //收集ArrayList<Student>
        //List<Students> list = is.collect(Collectors.toList());
        //System.out.println(list); // 全部放到一个集合当中

        //收集ArrayList<String>
        //List<String> ns = is.map(Students::getName).collect(Collectors.toList());
        //System.out.println(ns);  // 收集所有名字  将名字放到一个集合当中

        //count统计个数
        //System.out.println(is.filter(e -> "男".equals(e.getSex())).count());
        //System.out.println(is.filter(e -> "女".equals(e.getSex())).collect(Collectors.counting()));
        //System.out.println(is.filter(e -> e.getAge() <= 18).collect(Collectors.counting()));

        //求年龄最大的信息(Student) maxBy(升序）求最大  minBy(升序）求最小  max(降序）是求最小
        //System.out.println(is.max(Comparator.comparingInt(Students::getAge)).get());
        //System.out.println(is.collect(Collectors.maxBy((a, b) -> a.getAge() - b.getAge())).get());
        //求出最小年龄值是多少岁
        //System.out.println(is.max((a, b) -> b.getAge() - a.getAge()).get().getAge());
        //System.out.println(is.collect(Collectors.maxBy((a, b) -> b.getAge() - a.getAge())).get().getAge());

        //收集所有学生年龄总和，是一个int数字  summingInt summingLong summingDouble求和
        //System.out.println((Integer) is.mapToInt(Students::getAge).sum());
        //System.out.println(is.collect(Collectors.summingInt(Students::getAge)));

        //平均年龄  32.5  averageInt averageLong averageDouble求平均值
        //System.out.println(is.collect(Collectors.averagingInt(Students::getAge)));

        //一个次统计出所有信息 个数，最大，最小，平均，求和
//        var iss = is.collect(Collectors.summarizingInt(Students::getAge));
//        System.out.println(iss.getSum());
//        System.out.println(iss.getAverage());
//        System.out.println(iss.getMax());
//        System.out.println(iss.getMin());
//        System.out.println(iss.getCount());

        // joining 字符串拼接
        //System.out.println(is.map(Student::getName).collect(Collectors.toList()));
        //System.out.println(is.map(Students::getName).collect(Collectors.joining("-")));

        //分组groupingBy() 分组统计男多少人 女多少人
        //Map<String, Long> map = is.collect(Collectors.groupingBy(Students::getSex, Collectors.counting()));
        //System.out.println(map);

        //分组goupingBy() 组件学生信息 Map<String, List<Students>>
        //Map<String, List<Students>> mm = is.collect(Collectors.groupingBy(Students::getSex));
        //System.out.println(mm);

        //Map<String,List<String>>  mm 女 = [李丽],男=[李四,王五]

        //分区操作
        var mm = is.collect(Collectors.partitioningBy(e -> e.getName().startsWith("李")));
        System.out.println(mm);
    }


    // ↑   终止操作
    //    ????
    //    ????
    //    ????
    //    ????//    ????//    ????
    //    ????
    //    ????

    //   中间操作   ↓


    public static void main4(String[] args) {
     /*
     消费
        peek: 如同map, 能得到流中的每一个元素, 但是map就收的是一个Function表达式, 有返回值,
            而peek接收的是Consumer表达式,没有返回值(及消费者,用一次就销毁)
      */
        Stream<Students> studentsStream = Stream.of(new Students(1, "李四", "男", 21), new Students(2, "张三", "男", 18));

        studentsStream.peek(o -> o.setAge(o.getAge() + 5)).forEach(System.out::println);

        studentsStream.map(o -> {
            o.setAge(o.getAge() + 5);
            return o;
        }).forEach(System.out::println);

        // 两种方法都可行  但是 idea 建议使用peek方法
    }

    public static void main3(String[] args) {

        /*
            排序
                sorted(): 自然排序, 流中元素虚实线Comparable接口
                sorted(Comparator com): 定制排序, 自定义比较器
         */
        List<String> list = Arrays.asList("aa", "bb", "ff", "dd");
        list.stream().sorted().forEach(System.out::println);

        // 根据字符串长短进行排序
        List<String> list1 = Arrays.asList("aasda", "bb1", "f", "dd");
        Stream<String> sorted = list1.stream().sorted(((o1, o2) -> o2.length() - o1.length()));
        sorted.forEach(System.out::println);
    }

    public static void main2(String[] args) {

        /*
        映射
            map: 接收一个函数作为参数, 该函数会被应用到每个元素上, 并将其映射成一个新的元素
            flatMap: 接收一个函数作为参数, 将流中的每一个值都换另一个流,然后把所有流连接成一个流
         */

        List<String> list = Arrays.asList("a,b,c", "1,2,3");

        // 将每个元素转成一个新的且不带逗号的元素
        Stream<String> stringStream = list.stream().map(s -> s.replaceAll(",", ""));
        stringStream.forEach(System.out::println);  //  abc 123

        Stream<String> stream1 = list.stream().flatMap(s -> {
            String[] split = s.split(",");
            return Arrays.stream(split);
        });
        stream1.forEach(System.out::println); // a b c 1 2 3


    }

    public static void main1(String[] args) {

        /*
           filter: 过滤流中的某些元素
          limit(n): 获取n个元素
          skip(n): 跳过n个元素,配合limit(n)实现分页
         distinct: 通过流中元素的hashCode()和equals()去除重复元素
        */

        Stream<Integer> stream = Stream.of(2, 4, 6, 1, 3, 2, 56, 76, 12, 1, 5);

        Stream<Integer> newStream = stream.filter(s -> s > 5)  // 6 56 76 12
                .distinct()     // 6 56 76 12
                .skip(2)    // 76 12
                .limit(1);  // 76
        newStream.forEach(System.out::println);   // 76

    }
}
